﻿using DotNetCommon.Extensions;
using NUnit.Framework;
using Shouldly;
using System;
using System.ComponentModel.DataAnnotations.Schema;

namespace Test.MySql.ColumnTypeTests
{
    [TestFixture]
    internal class ColumnTypesTestsDateTime : TestBase
    {
        #region 模型
        [Table("test")]
        public class Model
        {
            /// <summary>
            /// mysql列类型: year
            /// </summary>
            public int? t_year { get; set; }

            /// <summary>
            /// mysql列类型: date
            /// </summary>
            public DateTime? t_date { get; set; }

            /// <summary>
            /// mysql列类型: datetime 链接字符串中添加 ConvertZeroDateTime=True
            /// </summary>
            public DateTime? t_datetime { get; set; }

            /// <summary>
            /// mysql列类型: timestamp
            /// </summary>
            public DateTime? t_timestamp { get; set; }

            /// <summary>
            /// mysql列类型: time
            /// </summary>
            public TimeSpan? t_time { get; set; }
        }

        [Table("test")]
        public class ModelDateOnlyTimeOnly
        {
            /// <summary>
            /// mysql列类型: date
            /// </summary>
            public DateOnly t_date { get; set; }

            /// <summary>
            /// mysql列类型: time
            /// </summary>
            public TimeOnly? t_time { get; set; }

            /// <summary>
            /// mysql列类型: timestamp
            /// </summary>
            public DateOnly? t_timestamp { get; set; }
        }

        [Table("test")]
        public class ModelTimeWithDay
        {
            /// <summary>
            /// mysql列类型: time
            /// </summary>
            public TimeSpan? t_time { get; set; }
        }
        #endregion

        [SetUp]
        public void Setup()
        {
            DropTableIfExist("test");
            db.ExecuteSql(@"
            create table test.test(
            	t_year int,
                t_date date,
                t_datetime datetime(6),
                t_timestamp timestamp(6),
                t_time time(6)
            )");
            db.ExecuteSql("insert into test.test(t_year,t_date,t_datetime,t_timestamp,t_time) values(2024,'2024-02-19','2024-02-19 22:40:12.123456','2024-02-19 22:40:12.654321','1:12:13.123456')");
        }

        [Test]
        public void TestDefaultParse()
        {
            var dic = db.SelectDictionary("select * from test");
            var t_year = dic["t_year"];
            t_year.ShouldBe(2024);
            var t_year_type = t_year.GetType();
            t_year_type.ShouldBe(typeof(int));
            var t_date = dic["t_date"];
            t_date.ShouldBe(DateTime.Parse("2024-02-19"));
            var t_date_type = t_date.GetType();
            t_date_type.ShouldBe(typeof(DateTime));
            var t_datetime = dic["t_datetime"];
            t_datetime.ShouldBe(DateTime.Parse("2024-02-19 22:40:12.123456"));
            var t_datetime_type = t_datetime.GetType();
            t_datetime_type.ShouldBe(typeof(DateTime));
            var t_timestamp = dic["t_timestamp"];
            t_timestamp.ShouldBe(DateTime.Parse("2024-02-19 22:40:12.654321"));
            var t_timestamp_type = t_timestamp.GetType();
            t_timestamp_type.ShouldBe(typeof(DateTime));
            var t_time = dic["t_time"];
            t_time.ShouldBe(TimeSpan.Parse("1:12:13.123456"));
            var t_time_type = t_time.GetType();
            t_time_type.ShouldBe(typeof(TimeSpan));
        }

        [Test]
        public void TestOrmRead()
        {
            var models = db.SelectModelList<Model>("select * from test");
            models[0].t_year.ShouldBe(2024);
            models[0].t_date.ShouldBe(DateTime.Parse("2024-02-19"));
            models[0].t_datetime.ShouldBe(DateTime.Parse("2024-02-19 22:40:12.123456"));
            models[0].t_timestamp.ShouldBe(DateTime.Parse("2024-02-19 22:40:12.654321"));
            models[0].t_time.ShouldBe(TimeSpan.Parse("1:12:13.123456"));
        }

        [Test]
        public void TestOrmWrite()
        {
            var models = db.SelectModelList<Model>("select * from test");
            validate(models[0]);
            TruncateTable("test");

            var sql = db.Insert("test", models[0].ToDictionary()).ToSql();
            var res = db.Insert("test", models[0].ToDictionary()).ExecuteAffrows();
            res.ShouldBe(1);
            models = db.SelectModelList<Model>("select * from test");
            validate(models[0]);

            void validate(Model model)
            {
                model.t_year.ShouldBe(2024);
                model.t_date.ShouldBe(DateTime.Parse("2024-02-19"));
                model.t_datetime.ShouldBe(DateTime.Parse("2024-02-19 22:40:12.123456"));
                model.t_timestamp.ShouldBe(DateTime.Parse("2024-02-19 22:40:12.654321"));
                model.t_time.ShouldBe(TimeSpan.Parse("1:12:13.123456"));
            }
        }

        [Test]
        public void TestDateOnlyTimeOnlyRead()
        {
            var models = db.SelectModelList<ModelDateOnlyTimeOnly>("select * from test");
            validate(models[0]);
            void validate(ModelDateOnlyTimeOnly model)
            {
                model.t_date.ShouldBe(DateOnly.Parse("2024-02-19"));
                model.t_time.ShouldBe(TimeOnly.Parse("1:12:13.123456"));
                model.t_timestamp.ShouldBe(DateOnly.Parse("2024-02-19"));
            }
        }

        [Test]
        public void TestDateOnlyTimeOnlyWrite()
        {
            var models = db.SelectModelList<ModelDateOnlyTimeOnly>("select * from test");
            validate(models[0]);

            TruncateTable("test");
            var sql = db.Insert("test", models[0].ToDictionary()).ToSql();
            var res = db.Insert("test", models[0].ToDictionary()).ExecuteAffrows();
            res.ShouldBe(1);
            models = db.SelectModelList<ModelDateOnlyTimeOnly>("select * from test");
            validate(models[0]);
            void validate(ModelDateOnlyTimeOnly model)
            {
                model.t_date.ShouldBe(DateOnly.Parse("2024-02-19"));
                model.t_time.ShouldBe(TimeOnly.Parse("1:12:13.123456"));
                model.t_timestamp.ShouldBe(DateOnly.Parse("2024-02-19"));
            }
        }

        [Test]
        public void TestTimeWithDay()
        {
            TruncateTable("test");
            db.Insert<ModelTimeWithDay>().SetEntity(new ModelTimeWithDay()
            {
                t_time = TimeSpan.Parse("12.1:2:3.123456")
            }).ExecuteAffrows();
            var models = db.SelectModelList<ModelTimeWithDay>("select * from test");
            models[0].t_time.Value.ShouldBe(TimeSpan.Parse("12.1:2:3.123456"));
        }
    }
}
